#include "StdAfx.h"
#include "Async_Result.h"
#include "Win32_Proactor.h"

Win32_Proactor::Win32_Proactor(size_t number_of_threads)
	: completion_port_(0),
	  number_of_threads_ (static_cast<DWORD> (number_of_threads))
{
	this->completion_port_ = 
		::CreateIoCompletionPort(INVALID_HANDLE_VALUE, 0, 0, this->number_of_threads_);

	int error = ::GetLastError();

	if(this->completion_port_ == 0)
	{
		LOG_ERROR(("RegisterIoCompletionPort(%d)", error));
	}
}

Win32_Proactor::~Win32_Proactor(void)
{
}

bool Win32_Proactor::register_handle(HANDLE _handle, const void* completion_key)
{
	ULONG comp_key(reinterpret_cast<ULONG> (completion_key));

	HANDLE regist_handle = ::CreateIoCompletionPort(_handle, this->completion_port_, 0, 0);

	int error = ::GetLastError();
	if(0 == regist_handle)
	{
		LOG_ERROR(("RegisterIoCompletionPort(%d)", error));
		return false;
	}

	return true;
}

int Win32_Proactor::handle_events(const Time_Value time_value)
{
	OVERLAPPED* overlappd = 0;
	ULONG completion_key = 0;
	u_long bytes_transferred = 0;

	BOOL result = ::GetQueuedCompletionStatus(this->completion_port_, 
											 &bytes_transferred,
											 &completion_key, 
											 &overlappd, 
											 time_value);

	if(FALSE == result && 0 == overlappd )
	{
		::GetLastError ();

		switch(errno)
		{
		case WAIT_TIMEOUT:
			errno = ERROR_SEM_TIMEOUT;
			return false;
		case ERROR_SUCCESS:
			return 0;
		default:
			LOG_ERROR(("GetQueuedCompletionStatus"));
			return -1;
		}
	}

	Async_Result* async_result = (Async_Result*)overlappd;

	if(FALSE == result) 
		::GetLastError();
	else 
		errno = 0;
	
	u_long result_err = async_result->error();
	
	if (result_err == 0)
		result_err = errno;

	this->result_process(async_result,
						 static_cast<size_t>(bytes_transferred),
					     (void*)completion_key,
						 result_err);

	return true;
}

void Win32_Proactor::result_process(Async_Result *async_result, 
												 size_t bytes_transferred, 
											     const void *completion_key, u_long error)
{
	__try
	{
		async_result->complete(bytes_transferred, 
			                   completion_key, 
							   error);
	}
	__finally
	{
		delete async_result;
	}
}